<template>
  <div>
    <el-dialog
      title="上传文件"
      :visible.sync="openDia"
      width="50%"
      :close-on-click-modal="false"
    >
      <el-upload
        drag
        action="#"
        multiple
        :auto-upload="false"
        :on-change="handleFileChange"
        :show-file-list="false"
      >
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处，或<em>点击上传</em></div>
      </el-upload>
      <el-button style="float: left;margin-bottom: 5px;" type="primary" size="mini" @click="handleAllUpload">一键上传</el-button>
      <el-table :data="fileList" style="width: 100%" border>
        <el-table-column prop="name" label="文件名" />
        <el-table-column prop="size" label="文件大小">
          <template slot-scope="scope">
            {{ formatFileSize(scope.row.size) }}
          </template>
        </el-table-column>
        <el-table-column prop="progress" label="上传进度">
          <template slot-scope="scope">
            <el-progress :color="scope.row.progress >= 100 ? '#67C23A' : '#409EFF'" :percentage="scope.row.progress"></el-progress>
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template slot-scope="scope">
            <el-link type="danger" @click="handleRemoveFile(scope.$index)" :disabled="scope.row.progress != 0 || scope.row.status != 'ready'">删除</el-link>
            <el-link type="success" @click="handleUploadFile(scope.$index)" :disabled="scope.row.status != 'ready'">上传</el-link>
          </template>
        </el-table-column>
      </el-table>
      <span slot="footer">
        <el-button @click="openDia = false">关 闭</el-button>
      </span>
    </el-dialog>
  </div>
</template>
<script>
import { formatFileSize, getFileMd5 } from "../../utils"
import SuperTask from "../../utils/superTask"
import axios from 'axios'
export default {
  props: {
    open: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      fileList: [],
      uploadQueue: new SuperTask(3),
      partSize: 5 * 1024 * 1024
    }
  },
  computed: {
    openDia: {
      get() {
        return this.open;
      },
      set(val) {
        this.$emit("update:open", val);
      },
    },
  },
  methods: {
    formatFileSize,
    handleFileChange(file) {
      if (this.fileList.length == 10) {
        this.$message.error("文件已超过10个,暂时不允许添加")
        return
      }
      file.progress = 0
      this.fileList.push({...file})
    },
    handleRemoveFile(idx) {
      this.fileList.splice(idx, 1)
    },
    handleUploadFile(idx) {
      this.fileList[idx].status = 'uploading'
      this.uploadQueue.add(this.uploadFile(this.fileList[idx]))
    },
    async handleAllUpload() {
      this.fileList.forEach(e => {
        if (e.status == 'ready') {
          e.status = 'uploading'
          this.uploadQueue.add(this.uploadFile(e))
        }
      })
      await this.uploadQueue.waitOver()
      this.$message.success("文件已全部上传完毕")
    },
    uploadFile(file) {
      return () => { return new Promise(async resolve => {
        const md5 = await getFileMd5(file.raw)
        if (md5.code == "error") {
          this.$message.error(`${file.name}md5计算失败`)
          file.status = "ready"
          resolve()
        }
        if (file.size <= this.partSize) {
          let formData = new FormData()
          formData.append('file', file.raw)
          // 小文件上传
          const res = await axios({
            url: 'http://192.168.10.191:8081/file/upload',
            method: 'POST',
            data: formData,
            onUploadProgress: (e) => {
              const progress = Math.floor((e.loaded / e.total) * 100)
              file.progress = progress > 98 ? 98 : progress
            },
          })
          if (res.data.code == 200) {
            file.progress = 100
            file.status = "done"
          } else {
            file.progress = 0
            file.status = "error"
            this.$message.error(`${file.name}上传失败`)
          }
        } else {
          // 大文件分片上传
          // 获取上传ID
          let uploadId = ''
          const uploadIdRes = await axios({
            url: 'http://192.168.10.191:8081/file/initPart',
            method: 'GET',
            params: {
              fileName: file.name
            }
          })
          if (uploadIdRes.data.code == 200) {
            uploadId = uploadIdRes.data.data
          } else {
            this.$message.error(`${file.name}获取上传ID失败`)
            resolve()
          }
          let start = 0
          let chunk = 0
          let end = this.partSize + start
          let chunks = Math.ceil(file.size / this.partSize)
          let formData = new FormData()
          formData.append("uploadId", uploadId)
          formData.append("file", null)
          formData.append("partNumber", chunk + 1)
          formData.append("fileName", file.name)
          // 上传分片
          while (chunk < chunks) {
            formData.set("partNumber", ++chunk)
            formData.set("file", file.raw.slice(start, end))
            const res = await axios({
              url: 'http://192.168.10.191:8081/file/uploadPart',
              method: 'POST',
              data: formData,
              onUploadProgress: (e) => {
                const progress =  Math.floor((chunk - 1 + e.loaded / e.total) * this.partSize * 100 / file.size)
                file.progress = progress > 98 ? 98 : progress
              },
            })
            if (res.data.code == 200) {
              start = end
              end += this.partSize
              if (chunk == chunks) {
                // 合并分片
                const mergeRes = await axios({
                  url: 'http://192.168.10.191:8081/file/merge',
                  method: 'GET',
                  params: {
                    uploadId,
                    fileName: file.name
                  }
                })
                if (mergeRes.data.code == 200) {
                  file.progress = 100
                  file.status = "done"
                } else {
                  file.progress = 0
                  file.status = "error"
                  this.$message.error(`${file.name}上传失败`)
                }
              }
            } else {
              this.$message.error(`${file.name},分片${chunk}上传失败`)
              await axios({url: 'http://192.168.10.191:8081/file/over', method: 'GET', params: { uploadId, fileName: file.name }})
              chunk = chunks
              resolve()
            }
          }
        }
        resolve()
      })
    }}
  }
}
</script>
<style scoped>
.el-link + .el-link {
  margin-left: 5px;
}
</style>